﻿// SetupByMiniBlink.cpp : 定义静态库的函数。
//
#include <thread>
#include <cassert>
#include <string>
#include "framework.h"
#include <Windows.h>
#include <objbase.h>
#include <gdiplus.h>
#include <ShlObj.h>
#include "COnlineMiniBlink.h"
#include "SetupByMiniBlink.h"
#pragma comment(lib ,"gdiplus.lib")
using namespace std;
using namespace Gdiplus;


CONST UINT WM_TryCreateWebView = WM_USER + 0x100;
// 全局变量:
HINSTANCE hInst;                                // 当前实例
LPCWSTR szWindowClass = L"SetupByMiniBlink";
HWND g_hWnd=NULL;                                      //主窗口句柄
COnlineMiniBlink* g_pOnlineMiniBlink=NULL;
Image* g_Image = NULL;

ATOM                MyRegisterClass(HINSTANCE hInstance,UINT iconId);
BOOL                InitInstance(HINSTANCE, LPCWSTR szTitle);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
void  ShowImage(HWND hWnd, Image* image, bool* toStop);
extern bool IsFileOrDirExists(LPCWSTR name);


void LoadNode(LPCWSTR nodeVersion,LPCSTR nodeUrl,LPCSTR mainUrl) {
    assert(g_pOnlineMiniBlink != NULL);

    WCHAR tempPath[MAX_PATH] = { 0 };

    //准备目录:临时文件夹+\\nodeVersion
    GetTempPath(MAX_PATH, tempPath);
    wstring nodeDir(tempPath);
    nodeDir.append(nodeVersion);
    if (!IsFileOrDirExists(nodeDir.c_str())) {
        CreateDirectory(nodeDir.c_str(), NULL);
    }
    wstring nodePath(nodeDir);
    nodePath.append(L"\\node.dll");
    if (!IsFileOrDirExists(nodePath.c_str())) {
        bool showImageThreadToStop = false;
        thread showImageThread(ShowImage, g_hWnd, g_Image, &showImageThreadToStop);
        //showImageThread.detach();
        g_pOnlineMiniBlink->OnLoadNode(nodeVersion, nodeUrl);
        showImageThreadToStop = true;
        showImageThread.join();
    }
    else {
        g_pOnlineMiniBlink->OnLoadNode(nodeVersion, nodeUrl);
    }
    SendMessage(g_hWnd, WM_TryCreateWebView, (WPARAM)mainUrl, 0);
}
void TryCreateWebView(LPCSTR mainUrl) {
    g_pOnlineMiniBlink->m_WebView = g_pOnlineMiniBlink->OnCreateWebView(g_hWnd);
    UINT width = GetSystemMetrics(SM_CXSCREEN);
    UINT height = GetSystemMetrics(SM_CYSCREEN);
    SetWindowPos(g_hWnd, HWND_TOP, 0, 0, width, height, SWP_SHOWWINDOW);
    g_pOnlineMiniBlink->OnLoadMainUrl(g_hWnd, mainUrl);
}
LRESULT CALLBACK OnWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    if (g_pOnlineMiniBlink != NULL && g_pOnlineMiniBlink->GetWebView() != NULL) {
        return g_pOnlineMiniBlink->OnWndProc(hWnd, message, wParam, lParam);
    }
    return FALSE;
}
void ClearHdc(HDC hMemDC,int width,int height) {
    // Clear hMemDC with window background color
    RECT fillRc{ 0, 0, width , height };
    LOGBRUSH lb;
    lb.lbColor = RGB(0, 0, 0);
    lb.lbStyle = BS_SOLID;
    lb.lbHatch = 0;
    HBRUSH brush = CreateBrushIndirect(&lb);
    FillRect(hMemDC, &fillRc, brush);
}
void Render(HWND hWnd,HDC hdc,HDC hMemDC){
    POINT ptSrc = { 0,0 };
    BLENDFUNCTION Blend;  //该BLENDFUNCTION结构控制通过指定源和目的地的位图的混合函数共混
    Blend.BlendOp = AC_SRC_OVER; //源混合操作。目前，唯一定义的源和目标混合操作是AC_SRC_OVER
    Blend.BlendFlags = 0; //必须为零
    Blend.AlphaFormat = AC_SRC_ALPHA; //该成员控制源和目标位图的解释方式
    Blend.SourceConstantAlpha = 255;//指定要在整个源位图上使用的Alpha透明度值
    RECT winRect;
    GetWindowRect(g_hWnd, &winRect);
    POINT ptDst = { winRect.left, winRect.top };
    SIZE size = { winRect.right - winRect.left,winRect.bottom - winRect.top };
    UpdateLayeredWindow(hWnd, hdc, &ptDst, &size, hMemDC, &ptSrc, NULL, &Blend, ULW_ALPHA);
}
void  ShowImage(HWND hWnd, Image* image,bool* toStop)
{
    int imageWidth = image->GetWidth();
    int imageHeight = image->GetHeight();
    HDC hdc = GetDC(hWnd);

    HDC hMemDC = CreateCompatibleDC(hdc);
    HBITMAP hMemBmp = CreateCompatibleBitmap(hdc, imageWidth, imageHeight);
    HBITMAP hOldMem = (HBITMAP)SelectObject(hMemDC, hMemBmp);

    UINT count = image->GetFrameDimensionsCount();
    GUID* pDimensionIDs = (GUID*)new GUID[count];
    image->GetFrameDimensionsList(pDimensionIDs, count);
    WCHAR strGuid[39];
    StringFromGUID2(pDimensionIDs[0], strGuid, 39);
    UINT frameCount = image->GetFrameCount(&pDimensionIDs[0]);
    delete[]pDimensionIDs;
    int size = image->GetPropertyItemSize(PropertyTagFrameDelay);
    static PropertyItem* pItem = (PropertyItem*)malloc(size);
    image->GetPropertyItem(PropertyTagFrameDelay, size, pItem);
    UINT fcount = 0;
    GUID Guid = FrameDimensionTime;
    Gdiplus::Graphics graphics(hMemDC);

    while (true)
    {
        ClearHdc(hMemDC, imageWidth, imageHeight);
        graphics.DrawImage(image, 0, 0, imageWidth, imageHeight);

        //StretchBlt(hdc, 0, 0, kInstallInterfaceWidth, kInstallInterfaceHeight, hMemDC, 0, 0, kInstallInterfaceWidth, kInstallInterfaceHeight, SRCCOPY);
        //BitBlt(hdc, 0, 0, imageWidth, imageHeight, hMemDC, 0, 0, SRCCOPY);
        Render(hWnd, hdc, hMemDC);

        image->SelectActiveFrame(&Guid, fcount++);
        if (fcount == frameCount)
            fcount = 0;

        long lPause = 1000 / frameCount;
        //long lPause = 50;
        Sleep(lPause);
        if (*toStop) {
            ClearHdc(hMemDC, imageWidth, imageHeight);
            Render(hWnd, hdc, hMemDC);
            break;
        }
    }
    SelectObject(hMemDC, hOldMem);
    ::DeleteObject(hMemBmp);
    ::DeleteObject(hMemDC);
    ReleaseDC(hWnd, hdc);
}

// TODO: 这是一个库函数示例
BOOL Run(HINSTANCE hInstance,UINT iconId,LPCWSTR szTitle, Image* loadingGifImage, LPCWSTR nodeVersion,LPCSTR nodeUrl,LPCSTR mainUrl,COnlineMiniBlink* pOnlineMiniBlink) {
    g_pOnlineMiniBlink = pOnlineMiniBlink;
    g_Image = loadingGifImage;
    assert(g_pOnlineMiniBlink != NULL);
    assert(g_Image != NULL);
    // 初始化全局字符串
    MyRegisterClass(hInstance, iconId);      

    // 执行应用程序初始化:
    if (!InitInstance(hInstance, szTitle))
    {
        return FALSE;
    }
    thread loadNodeThread(LoadNode, nodeVersion,nodeUrl,mainUrl);
    loadNodeThread.detach();
    MSG msg;

    // 主消息循环:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}
//
//  函数: MyRegisterClass()
//
//  目标: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance,UINT iconId)
{
    WNDCLASSW wcex;

    wcex.style = CS_HREDRAW | CS_VREDRAW|CS_OWNDC;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(iconId));
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszClassName = szWindowClass;
    wcex.lpszMenuName = NULL;

    return RegisterClassW(&wcex);
}

//
//   函数: InitInstance(HINSTANCE, int)
//
//   目标: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中，我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance,LPCWSTR szTitle)
{
    hInst = hInstance; // 将实例句柄存储在全局变量中
    int x, y, width, height;
    width = g_Image->GetWidth();
    height = g_Image->GetHeight();
    RECT desktopRect;
    SystemParametersInfo(SPI_GETWORKAREA, 0, &desktopRect, 0);
    x = (desktopRect.right - desktopRect.left - width) / 2+desktopRect.left;
    y = (desktopRect.bottom - desktopRect.top - height) / 2 + desktopRect.top;

    g_hWnd = CreateWindowEx(WS_EX_LAYERED, szWindowClass, szTitle, WS_POPUP,
        x, y, width, height, nullptr, nullptr, hInstance, nullptr);
    if (!g_hWnd)
    {
        return FALSE;
    }    
    ShowWindow(g_hWnd, SW_SHOW);
    //UpdateWindow(g_hWnd);
    //SetActiveWindow(g_hWnd);

    return TRUE;
}

//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目标: 处理主窗口的消息。
//
//  WM_COMMAND  - 处理应用程序菜单
//  WM_PAINT    - 绘制主窗口
//  WM_DESTROY  - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if (OnWndProc(hWnd, message, wParam, lParam))
        return TRUE;
    switch (message)
    {
    case WM_TryCreateWebView:
        TryCreateWebView((LPCSTR)wParam);
    break;
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        // TODO: 在此处添加使用 hdc 的任何绘图代码...
        EndPaint(hWnd, &ps);
    }
    break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return FALSE;
}
